<?php
/**
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * PHP Version 5
 *
 * @category Plate
 * @author   Wang Zhaogang <Wang Zhaogang@babamaiche.com>
 * @file     Plate.php
 * @date     2016/9/6
 * @time     11:30
 * @license  http://chedamai.cn/ License
 * @link     http://chedamai.cn/
 */
namespace app\components;
/**
 * The Plate class is used for ***
 *
 * @category Plate
 * @author   Wang Zhaogang <Wang Zhaogang@babamaiche.com>
 * @class    Plate
 * @date     2016/9/6
 * @time     11:30
 * @license  http://chedamai.cn/ License
 * @link     http://chedamai.cn/
 */

use yii;
use yii\log\Logger;
class Plate
{
    const HEIGHT = 5;
    private $width = 5;
    private $data = [];
    private $path = [];
    private $shapes = [];
    private $emptyBlocks = -1;

    /**
     * @return int
     */
    public function getEmptyBlocks()
    {
        return $this->emptyBlocks;
    }

    /**
     * Plate constructor.
     * @param int $width
     */
    public function __construct($width)
    {
        $this->width = $width;
        $this->emptyBlocks = self::HEIGHT * $this->width;
        for ($i = 0; $i < $this->width; $i++) {
            for ($j = 0; $j < self::HEIGHT; $j++) {
                $this->data[$j][$i] = 0;
            }
        }
    }

    public function putShape($shape, $x, $y)
    {
        $shapeArray = $shape->toArray();
        if ($x >= $this->width || $x < 0 || $y > self::HEIGHT || $y < 0) {
            return false;
        }
        //找到形状的左上角第一个不为空的点的坐标
        $firstX = 0;
        $firstY = 0;
        for ($i = 0; $i < $shapeArray['width']; $i++) {
            for ($j = 0; $j < $shapeArray['height']; $j++) {
                if ($shapeArray['data'][$j][$i] === 1) {
                    $firstX = $i;
                    $firstY = $j;
                }
            }
        }
        //检查是否能放下
        for ($i = 0; $i < $shapeArray['width']; $i++) {
            for ($j = 0; $j < $shapeArray['height']; $j++) {
                if ($shapeArray['data'][$j][$i] === 1) {
                    $newX = $x - $firstX + $i;
                    $newY = $y - $firstY + $j;
                    //是否超出底盘边界
                    if ($newX >= $this->width || $newX < 0 || $newY >= self::HEIGHT || $newY < 0) {
                        return false;
                    }
                    //是否已经放过其它形状
                    if ($this->data[$newY][$newX] === 1) {
                        return false;
                    }
                }
            }
        }
        //如果能够放下，则更新底盘，空格数量
        for ($i = 0; $i < $shapeArray['width']; $i++) {
            for ($j = 0; $j < $shapeArray['height']; $j++) {
                if ($shapeArray['data'][$j][$i] === 1) {
                    $newX = $x - $firstX + $i;
                    $newY = $y - $firstY + $j;
                    $this->data[$newY][$newX] = 1;
                    $this->emptyBlocks--;
                }
            }
        }
        //更新路径
        $node = [$shape, $x, $y, $firstX, $firstY];
        array_push($this->path, $node);
        return true;
    }

    public function popShape($debug = false) {
        $node = array_pop($this->path);
        if (!isset($node)) {
            return false;
        }
        $shape = $node[0];
        $x = $node[1];
        $y = $node[2];
        $shapeArray = $shape->toArray();
        if ($debug) {
            Yii::getLogger()->log('pop内部 array：' . print_r($shapeArray, true), Logger::LEVEL_INFO);
            Yii::getLogger()->log('pop内部 plate：' . print_r($this->data, true), Logger::LEVEL_INFO);
        }
        //找到形状的左上角第一个不为空的点的坐标
        $firstX = 0;
        $firstY = 0;
        for ($i = 0; $i < $shapeArray['width']; $i++) {
            for ($j = 0; $j < $shapeArray['height']; $j++) {
                if ($shapeArray['data'][$j][$i] === 1) {
                    $firstX = $i;
                    $firstY = $j;
                }
            }
        }
        for ($i = 0; $i < $shapeArray['width']; $i++) {
            for ($j = 0; $j < $shapeArray['height']; $j++) {
                if ($shapeArray['data'][$j][$i] === 1) {
                    $newX = $x - $firstX + $i;
                    $newY = $y - $firstY + $j;
                    $this->data[$newY][$newX] = 0;
                    $this->emptyBlocks++;
                }
            }
        }
        return $node;
    }
    public static function nodeToHash($node) {
        $shape = $node[0];
        $x = $node[1];
        $y = $node[2];
        return $shape->toHash() * 1000 + $y * self::HEIGHT + $x;
    }
    public function getEmptyPositions() {
        $ret = [];
        for ($i = 0; $i < $this->width; $i++) {
            for ($j = 0; $j < self::HEIGHT; $j++) {
                if ($this->data[$j][$i] === 0) {
                    $ret[] = [$i, $j];
                }
            }
        }
        return $ret;
    }
    public function getFirstEmptyPosition() {
        for ($i = 0; $i < $this->width; $i++) {
            for ($j = 0; $j < self::HEIGHT; $j++) {
                if ($this->data[$j][$i] === 0) {
                    return [$i, $j];
                }
            }
        }
        return false;
    }
    public function getPath() {
        return $this->path;
    }
    public function getResult() {
        $ret = [];
        foreach($this->path as $node) {
            $ret[] = [
                'shape' => $node[0]->toArray(),
                'x' => $node[1],
                'y' => $node[2],
                'firstX' => $node[3],
                'firstY' => $node[4],
            ];
        }
        return $ret;
    }
    public function getPathHash() {
        $ret = [];
        foreach($this->path as $node) {
            $ret[] = self::nodeToHash($node);
        }
        return $ret;
    }
    public function getData() {
        return $this->data;
    }
}